/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.util.op2parser.parsers.pyNastran;

import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.isfd.domain.*;
import com.comac.ins.isfd.domain.bo.IsfdMeshOp2SubcaseBo;
import com.fasterxml.jackson.databind.ObjectMapper;
import jep.NDArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.bson.Document;
import org.springframework.util.CollectionUtils;

import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

@Slf4j
public class PyNastranOP2Reader {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    public static final String VARIABLE = "VARIABLE";
    public static final String LOADCASE = "LOADCASE";
    public static final String ELEMENT = "E";
    public static final String NODE = "N";
    public static final String RESULT = "RESULT";

    public static Map readOP2(String filePath) {
        // 创建JSON格式字符串
        filePath = filePath.replace("\\", "/");
        if (filePath.startsWith("//") || filePath.startsWith("\\")) {
            filePath = filePath.replaceAll("^[/\\\\]+", "");  // 删除路径开头所有反斜杠或正斜杠
        }
        return OP2PythonExecutor.excute("parse_op2", filePath);
    }

    @SuppressWarnings("unchecked")
    public static IsfdMeshOp2Object convertToOP2Object(String filePath) {
        StopWatch stopWatch = StopWatch.createStarted();
        log.info("开始解析op2");
        // 获取文件名
        String fileName = Paths.get(filePath).getFileName().toString();
        // 解析结果数据，使用pyNastran
        Map parseResult = readOP2(filePath);

        if (CollectionUtils.isEmpty(parseResult)) {
            throw new BaseException("未解析出结果数据！文件：" + fileName);
        }
        // 转换数据
        String title = parseResult.get("title").toString();
        Map<String , Object> result = (Map<String, Object>) parseResult.get("result");
        List<IsfdMeshOp2Result> op2Results = new ArrayList<>();
        for (String key : result.keySet()) {
            List<IsfdMeshOp2SubcaseBo> subcaseList = new ArrayList<>();
            Map<?, Object> subcases = (Map<?, Object>) result.get(key);
            for (Map.Entry<?, Object> entry : subcases.entrySet()) {
                Integer subcaseId = ((Number) entry.getKey()).intValue();
                Map<String, Object> content = (Map<String, Object>) entry.getValue();
                // 结果数据
                NDArray<?> ndArrayData = (NDArray<?>) content.get("data");
                float[] dataArrayFlattened = (float[]) ndArrayData.getData();
                int[] dimensionDataArray = ndArrayData.getDimensions();
                if (dimensionDataArray.length != 3) {
                    throw new BaseException("数据结构存在问题, 检查解析");
                }
                // 单元id
                NDArray<?> ndArrayElement = (NDArray<?>) content.get("element");
                int[] elementArray = (int[]) ndArrayElement.getData();
                int[] dimensionElementArray = ndArrayElement.getDimensions();

                // 头信息
                List<String> headers = (List<String>) content.get("headers");
                if (headers.size() != dimensionDataArray[2]) {
                    throw new BaseException("Headers信息有误，检查解析");
                }

                if (dimensionElementArray[0] != elementArray.length ||
                    dimensionElementArray[0] != dimensionDataArray[1]) {
                    throw new BaseException("数据结构存在问题, 检查解析");
                }
                // 存储数据
                Map<Integer,float[]> resultMap = new HashMap<>();
                for (int i = 0; i < elementArray.length; i++) {
                    int elementId = elementArray[i];
                    int nColumn = dimensionDataArray[2];
                    // 获取当前元素对应的行数据，起始索引为 i *
                    float[] rowData = new float[nColumn];
                    System.arraycopy(dataArrayFlattened, i * nColumn, rowData, 0, nColumn);
                    // 使用 putIfAbsent 来简化检查和插入
                    if (resultMap.putIfAbsent(elementId, rowData) != null) {
                        throw new IllegalArgumentException("Duplicate elementId found: " + elementId);
                    }
                }
                // 返回
                IsfdMeshOp2SubcaseBo subcase = new IsfdMeshOp2SubcaseBo();
                subcase.setSubcaseId(subcaseId);
                subcase.setData(resultMap);
                subcase.setColumnQuantity(dimensionDataArray[2]);
                subcase.setElementQuantity(dimensionElementArray[0]);
                subcase.setHeaders(headers);
                subcaseList.add(subcase);
            }
            IsfdMeshOp2Result op2Result = new IsfdMeshOp2Result();
            op2Result.setResultName(key);
            op2Result.setSubcaseList(subcaseList);
            op2Results.add(op2Result);
        }

        // 构造返参
        IsfdMeshOp2Object isfdMeshOp2Object = new IsfdMeshOp2Object();
        isfdMeshOp2Object.setResultList(op2Results);

        // 计时
        stopWatch.stop();
        log.info("Task completed in {} milliseconds.", stopWatch.getTime());

        return isfdMeshOp2Object;
    }

    public static List<IsfdMeshOp2Record> convertToOP2RecordData(IsfdMeshOp2Object op2Object) {

        StopWatch stopWatch = StopWatch.createStarted();
        log.info("开始转换op2");

        List<IsfdMeshOp2Record> recordList = new ArrayList<>();
        for (IsfdMeshOp2Result op2Result : op2Object.getResultList()) {
            String resultName = op2Result.getResultName();

            for (IsfdMeshOp2SubcaseBo subcase : op2Result.getSubcaseList()) {
                List<IsfdMeshOp2Record> subcaseRecords = convertSubcaseToRecords(subcase, resultName);
                recordList.addAll(subcaseRecords);
            }
        }

        // 计时
        stopWatch.stop();
        log.info("Task completed in {} milliseconds.", stopWatch.getTime());

        return recordList;
    }

    public static List<IsfdMeshOp2Record> convertSubcaseToRecords(IsfdMeshOp2SubcaseBo subcase, String resultName){
        List<IsfdMeshOp2Record> recordList = new ArrayList<>();

        Integer subcaseId = subcase.getSubcaseId();

        IsfdMeshOp2RecordLoadcase recordLoadcase = new IsfdMeshOp2RecordLoadcase();
        recordLoadcase.setId(subcaseId);
        recordLoadcase.setClassName(LOADCASE);


        IsfdMeshOp2RecordVariable recordVariable = new IsfdMeshOp2RecordVariable();
        recordVariable.setClassName(VARIABLE);
        recordVariable.setName(resultName);
        int variableId = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE); // 生成一个variableId
        recordVariable.setId(variableId);

        recordLoadcase.setVariables(new Integer[]{variableId});

        recordList.add(recordLoadcase);
        recordList.add(recordVariable);


        Map<Integer, float[]> data = subcase.getData();
        for (Map.Entry<Integer, float[]> entry : data.entrySet()) {
            Integer id = entry.getKey();
            IsfdMeshOp2RecordElement recordElement = new IsfdMeshOp2RecordElement();
            recordElement.setId(id);
            recordElement.setClassName(ELEMENT);

            float[] record = entry.getValue();
            // 处理 key 和 value
            IsfdMeshOp2RecordData recordData = new IsfdMeshOp2RecordData();
            recordData.setClassName(RESULT);
//                    recordData.setVariable(variableId);
            recordData.setEntity(id);
            recordData.setValues(record);

            recordData.setLoadCase(subcaseId);
            recordData.setResultName(resultName);
//                    recordData.setHeaders(subcase.getHeaders());

            // 先不存element，没什么用
            // recordList.add(recordElement);
            recordList.add(recordData);
        }

        // 清理内存：data用完后清空
        subcase.setData(null);

        return recordList;
    }

    public static void main(String[] args) {
        String FILE_FOLDER = "D:\\结果文件\\计算结果\\计算结果\\wf-机翼（内力）\\";
        String FILE_NAME = "c919s_fw_wf_air_part_1.op2";
//        FILE_NAME = "check1_81.op2";

        String inputJson = FILE_FOLDER + FILE_NAME;

        IsfdMeshOp2Object op2Object = convertToOP2Object(inputJson);

        List<IsfdMeshOp2Record> recordList = convertToOP2RecordData(op2Object);

        long totalSize = getTotalSize(recordList);
        long dataSize = getObjectSize(recordList.get(100));
        long dataSize2 = getObjectSize(recordList.get(1000));

        String total = humanReadableSize(totalSize);
        String data = humanReadableSize(dataSize);
        String data2 = humanReadableSize(dataSize2);

        System.out.println("success");
    }


    public static long getObjectSize(Object object) {
        try {
            String jsonString = objectMapper.writeValueAsString(object); // 转为 JSON 字符串
            Document doc = Document.parse(jsonString); // 转为 BSON
            return doc.toJson().getBytes().length; // 计算字节大小
        } catch (Exception e) {
            throw new RuntimeException("计算 JSON 大小失败: " + e.getMessage(), e);
        }
    }

    public static long getTotalSize(List<?> dataList) {
        return dataList.stream().mapToLong(PyNastranOP2Reader::getObjectSize).sum();
    }

    public static String humanReadableSize(long bytes) {
        if (bytes < 1024) return bytes + " B"; // 小于 1KB 直接返回字节数
        int exp = (int) (Math.log(bytes) / Math.log(1024)); // 计算单位
        String unit = "KMGTPE".charAt(exp - 1) + "B"; // K、M、G、T...
        return String.format("%.2f %s", bytes / Math.pow(1024, exp), unit);
    }

}
